# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

import gtk
import gobject
import os
import pango
import sys
import xmmsclient
import re

import client
import img
import main

class PreferencesWindow(gtk.Dialog):

    """
    The preferences window
    """


    def __init__(self, control):
        gtk.Dialog.__init__(self)
        self.client = control.client
        self.control = control

        self.set_title(_("Etude")+" - " + _("Preferences"))
        self.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK )
        self.set_default_size(400, 480)

        self.notebook = gtk.Notebook()
        self.vbox.pack_start(self.notebook)
        
        gf = GeneralFrame(control)
        self.notebook.append_page(gf, gtk.Label(_("General")))
        
        au = AudioFrame(control)
        self.notebook.append_page(au, gtk.Label(_("Audio")))
        
        la = PluginsFrame(control)
        self.notebook.append_page(la, gtk.Label(_("Layout & Plugins")))
 
        ad = AdvancedFrame(control)
        self.notebook.append_page(ad, gtk.Label(_("Advanced")))

        sh = ShortcutsFrame(control)
        self.notebook.append_page(sh, gtk.Label(_("Shortcuts")))

        self.notebook.show()
        self.show()

class AudioFrame(gtk.Frame):

    """
    Audio settings
    """
    class AlsaFrame(gtk.Frame):

        def __init__(self, client):
            gtk.Frame.__init__(self)
            self.config = client.config

            table = gtk.Table(rows = 2, columns = 2)
            table.set_col_spacings(3)
            table.set_row_spacings(3)
            self.add(table)
            
            lab1 = gtk.Label(_("device"))
            lab2 = gtk.Label(_("mixer"))
            self.dev_entry = gtk.Entry()
            self.dev_entry.set_text(self.config['alsa.device'])
            self.mix_entry = gtk.Entry()
            self.mix_entry.set_text(self.config['alsa.mixer'])

            table.attach(lab1, 0, 1, 0, 1, xoptions = 0, yoptions = 0)
            table.attach(lab2, 0, 1, 1, 2, xoptions = 0, yoptions = 0)
            table.attach(self.dev_entry, 1, 2, 0, 1, xoptions = gtk.FILL, yoptions = gtk.FILL)
            table.attach(self.mix_entry, 1, 2, 1, 2, xoptions = gtk.FILL, yoptions = gtk.FILL)
            
            self.dev_entry.connect('activate', self.save_config)
            self.mix_entry.connect('activate', self.save_config)
            self.show_all()

        def save_config(self, widget=None, data = None):
            if widget == None or widget == self.dev_entry:
                self.config.set('alsa.device', self.dev_entry.get_text())
            if widget == None or widget == self.mix_entry:
                self.config.set('alsa.mixer', self.mix_entry.get_text())
            
    class OSSFrame(gtk.Frame):

        def __init__(self, client):
            gtk.Frame.__init__(self)
            self.config = client.config

            table = gtk.Table(rows = 3, columns = 2)
            table.set_col_spacings(3)
            table.set_row_spacings(3)
            self.add(table)
            
            lab1 = gtk.Label(_("device"))
            lab2 = gtk.Label(_("mixer"))
            #lab3 = gtk.Label(_("mixer device"))
            self.dev_entry = gtk.Entry()
            self.dev_entry.set_text(self.config['oss.device'])
            self.mix_entry = gtk.Entry()
            self.mix_entry.set_text(self.config['oss.mixer'])
            #self.mix_dev_entry = gtk.Entry()
            #self.mix_dev_entry.set_text(self.config['oss.mixer_dev'])

            table.attach(lab1, 0, 1, 0, 1, xoptions = 0, yoptions = 0)
            table.attach(lab2, 0, 1, 1, 2, xoptions = 0, yoptions = 0)
            #table.attach(lab3, 0, 1, 2, 3, xoptions = 0, yoptions = 0)
            table.attach(self.dev_entry, 1, 2, 0, 1, xoptions = gtk.FILL, yoptions = gtk.FILL)
            table.attach(self.mix_entry, 1, 2, 1, 2, xoptions = gtk.FILL, yoptions = gtk.FILL)
            #table.attach(self.mix_dev_entry, 1, 2, 2, 3, xoptions = gtk.FILL, yoptions = gtk.FILL)
            
            self.dev_entry.connect('activate', self.save_config)
            self.mix_entry.connect('activate', self.save_config)
            #self.mix_dev_entry.connect('activate', self.save_config)
            self.show_all()

        def save_config(self, widget=None, data = None):
            if widget == None or widget == self.dev_entry:
                self.config.set('oss.device', self.dev_entry.get_text())
            if widget == None or widget == self.mix_entry:
                self.config.set('oss.mixer', self.mix_entry.get_text())
            #if widget == None or widget == self.mix_dev_entry:
            #    self.config.set('oss.mixer_dev', self.mix_dev_entry.get_text())

    class AoFrame(gtk.Frame):

        def __init__(self, client):
            gtk.Frame.__init__(self)
            self.config = client.config

            table = gtk.Table(rows = 2, columns = 2)
            table.set_col_spacings(3)
            table.set_row_spacings(3)
            self.add(table)
            
            lab1 = gtk.Label(_("device"))
            lab2 = gtk.Label(_("driver"))
            self.dev_entry = gtk.Entry()
            self.dev_entry.set_text(self.config['ao.device'])
            self.driv_entry = gtk.Entry()
            self.driv_entry.set_text(self.config['ao.driver'])

            table.attach(lab1, 0, 1, 0, 1, xoptions = 0, yoptions = 0)
            table.attach(lab2, 0, 1, 1, 2, xoptions = 0, yoptions = 0)
            table.attach(self.dev_entry, 1, 2, 0, 1, xoptions = gtk.FILL, yoptions = gtk.FILL)
            table.attach(self.driv_entry, 1, 2, 1, 2, xoptions = gtk.FILL, yoptions = gtk.FILL)
            
            self.dev_entry.connect('activate', self.save_config)
            self.driv_entry.connect('activate', self.save_config)
            self.show_all()

        def save_config(self, widget=None, data = None):
            if widget == None or widget == self.dev_entry:
                self.config.set('ao.device', self.dev_entry.get_text())
            if widget == None or widget == self.driv_entry:
                self.config.set('ao.driver', self.driv_entry.get_text())
    
    class EmptyFrame(gtk.Frame):

        def __init__(self, client):
            gtk.Frame.__init__(self)
            self.config = client.config
            lab1 = gtk.Label(_("For settings use advanced settings tab"))
            self.add(lab1)

            self.show_all()

        def save_config(self, widget=None, data = None):
            pass

    def __init__(self, control):

        gtk.Frame.__init__(self)
        self.control =control
        self.client = control.client
        self.config = self.client.config
        
        self.set_shadow_type(gtk.SHADOW_NONE)
        self.set_property('border-width', 5)

        self.table = gtk.Table(rows = 3, columns = 2)
        self.table.set_col_spacings(3)
        self.table.set_row_spacings(3)
        self.add(self.table)
        lab1 = gtk.Label(_("Audio Output"))
        self.table.attach(lab1, 0, 1, 0, 1, xoptions = 0, yoptions = 0)
        curr_out = self.client.config['output.plugin']
        
        self.combo_model = gtk.ListStore( gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.combo = gtk.ComboBox(self.combo_model)
        self.table.attach(self.combo, 1, 2, 0, 1, yoptions = 0)
        cell = gtk.CellRendererText()
        self.combo.pack_start(cell, True)
        self.combo.add_attribute(cell, 'text', 0)
        for plugin in self.client.plugins.values():
            if plugin['type'] == xmmsclient.PLUGIN_TYPE_OUTPUT:
                iter = self.combo_model.append( (plugin['name'],plugin['shortname']) )
                if plugin['shortname'] == curr_out:
                    self.combo.set_active_iter(iter)
                    self.set_active_frame(plugin['shortname'])
        self.combo.connect('changed', self.output_changed)

        lab2 = gtk.Label(_("Buffer size"))
        self.table.attach(lab2, 0, 1, 2, 3, xoptions = 0, yoptions = 0)
        spin = gtk.SpinButton(climb_rate = 100.0)
        spin.set_range(0.0, 999999.0)
        spin.set_increments(100.0, 1000.0)
        spin.set_numeric(True)
        spin.set_value(float(self.client.config['output.buffersize']))
        self.table.attach(spin, 1, 2, 2, 3, xoptions = 0, yoptions = 0)
        spin.connect('value-changed', self.buffersize_changed)

        self.show_all()

    def buffersize_changed(self, spin, data = None):
        self.client.config.set('output.buffersize', spin.get_value_as_int())
        return False

    def set_active_frame(self, active):
        """active = short_name of the plugin"""
        try:
            self.table.remove(self.prev_out_widget)
        except AttributeError:
            pass

        if active == 'alsa':
            f = self.AlsaFrame(self.client)
        elif active == 'oss':
            f = self.OSSFrame(self.client)
        elif active == 'ao':
            f = self.AoFrame(self.client)
        else:
            f = self.EmptyFrame(self.client)
        self.prev_out_widget = f
        self.table.attach(f, 0, 2, 1, 2, xoptions = gtk.FILL, yoptions = 0)

    def output_changed( self, combo, data = None):

        it = combo.get_active_iter()
        active = self.combo_model.get_value(it, 1)
        self.set_active_frame(active)
        self.client.config.set('output.plugin', active)
        return False

class ProfilesFrame(gtk.Frame):

    def __init__(self, control, connect_button = True):
        gtk.Frame.__init__(self, label=_("Profiles"))
        self.control = control
        self.config = control.config
        self.profs = control.profile
        self.set_shadow_type(gtk.SHADOW_IN)

        self.combo = gtk.combo_box_entry_new_text()
        try:
            cname = self.profs['name']
        except KeyError:
            cname = self.profs.default
        profiles = self.profs.profiles.keys()
        profiles.sort()
        active = 0
        for prof_index in xrange(len(profiles)):
            self.combo.append_text(profiles[prof_index])
            if profiles[prof_index] == cname:
                active = prof_index
        
        self.url_entry = gtk.Entry()
        self.music_dir_entry = gtk.Entry()
        
        self.default = gtk.CheckButton(_("Default"))
        self.stop_daemon = gtk.CheckButton(_("Stop daemon on exit"))
        self.start_daemon = gtk.CheckButton(_("Automatically start daemon"))
        
        self.combo.connect('changed', self.combo_changed)
        try:
            self.combo.set_active(active)
        except:
            print(sys.exc_info())

        self.table = gtk.Table(rows = 6, columns = 2)
        self.table.attach(gtk.Label(_("Profile")+":"), 0,1, 0,1, xoptions=gtk.FILL, yoptions=0)
        self.table.attach(self.combo, 1,2, 0,1, xoptions=gtk.FILL| gtk.EXPAND, yoptions=0)
        self.table.attach(gtk.Label(_("Url")+":"), 0,1, 1,2, xoptions=gtk.FILL, yoptions=0)
        self.table.attach(self.url_entry, 1,2, 1,2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)
        self.table.attach(gtk.Label(_("Music Directory")+":"), 0,1, 2,3, xoptions=gtk.FILL, yoptions=0)
        self.table.attach(self.music_dir_entry, 1,2, 2,3, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)
        self.table.attach(self.stop_daemon, 1,2, 3,4, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)
        self.table.attach(self.start_daemon, 1,2, 4,5, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)

        hbox = gtk.HBox()
        save_button = gtk.Button( stock = gtk.STOCK_SAVE)
        remove_button = gtk.Button( stock = gtk.STOCK_REMOVE)

        hbox.pack_end(save_button, False, False)
        hbox.pack_end(remove_button, False, False)
        self.table.attach(hbox, 0, 2, 5, 6, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL)

        save_button.connect('clicked', self.on_save_profile)
        remove_button.connect('clicked', self.on_remove_profile)
        
        if connect_button:
            connection_button = gtk.Button( stock = gtk.STOCK_CONNECT)
            connection_button.connect('clicked', self.on_load_profile)
            hbox.pack_start(connection_button, False, False)
        hbox.pack_start(self.default, False, False)

        self.add(self.table)

        self.show_all()


    def combo_changed(self, widget, data= None):
        dic = self.profs.get_profile(widget.get_active_text())
        self.url_entry.set_text(dic['url'])
        self.music_dir_entry.set_text(dic['music_dir'])
        self.default.set_active(dic['default'])
        self.stop_daemon.set_active(dic['stop_daemon'])
        if dic['remote'] == False:
            self.start_daemon.set_active(dic['start_daemon'])
            self.start_daemon.set_sensitive(True)
        else:
            self.start_daemon.set_active(False)
            self.start_daemon.set_sensitive(False)

    def on_save_profile(self, widget=None, data =None):
        name = self.combo.get_active_text()

        if name == '':
            return True

        prof = {}
        prof['default'] = self.default.get_active()
        prof['stop_daemon'] = self.stop_daemon.get_active()
        prof['start_daemon'] = self.start_daemon.get_active()
        prof['url'] = self.url_entry.get_text()
        prof['music_dir'] = self.music_dir_entry.get_text()
        if not self.profs.profile_exists(name):
            self.combo.append_text(name)
        self.profs.save_profile(name, prof)
        return False
    
    def on_load_profile(self, widget = None, data = None):
        if self.on_save_profile():
            self.show_connection_error(_("Please set a name for the profile!"))
            return True
        name = self.combo.get_active_text()
        if self.control.client.xmms != None:
            self.control.disconnected(profile=name)
            return False
        if self.profs.load_profile(name) == False:
            return True
        return False

    def on_remove_profile(self, widget = None, data = None):
        name = self.combo.get_active_text()
        index = self.combo.get_active()

        if name == '' or index == -1:
            return True

        self.profs.remove_profile(name)
        self.combo.remove_text(index)

    def show_connection_error(self, secondary = ''):
        """
        show an error

        should have a global one for this
        """
        dialog = gtk.MessageDialog(parent = self.get_toplevel(), buttons= gtk.BUTTONS_CLOSE,
                flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, 
                type = gtk.MESSAGE_ERROR)
        dialog.set_markup(_("Error occured while connecting"))
        dialog.format_secondary_markup(secondary)
        dialog.run()
        dialog.destroy()

class GeneralFrame(gtk.Frame):

    """
    General settings
    """

    def __init__(self, control):

        gtk.Frame.__init__(self)
        self.control =control
        self.client = control.client
        
        self.set_shadow_type(gtk.SHADOW_NONE)

        vbox = gtk.VBox()
        self.add(vbox)

        proframe = ProfilesFrame(self.control)
        vbox.pack_start(proframe, False, False)

        self.show_all()


class PluginsFrame(gtk.Frame):

    """
    Plugins and layouts
    """

    def __init__(self, control):

        gtk.Frame.__init__(self)
        self.control = control
        self.config = control.config
        
        self.set_shadow_type(gtk.SHADOW_NONE)

        vbox = gtk.VBox()
        self.add(vbox)

        attrlist = pango.AttrList()
        w = pango.AttrWeight( pango.WEIGHT_BOLD, 0, -1)
        s = pango.AttrScale( 1.1, 0, -1)
        attrlist.insert(s)
        attrlist.insert(w)

        label = gtk.Label(_("Layout"))
        label.set_attributes(attrlist)
        tbox = gtk.HBox()
        tbox.pack_start(label, False, False)
        vbox.pack_start(tbox, False, False, 5)

        hbox = gtk.HBox()
        vbox.pack_start(hbox, False, False)
        layout_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
        layout_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
        self.layout_combo = gtk.ComboBox(layout_model)
        hbox.pack_start(self.layout_combo, True, True)
        cell = gtk.CellRendererText()
        self.layout_combo.pack_start(cell, True)
        self.layout_combo.add_attribute(cell, 'text', 0)

        self.__fill_layout(layout_model)
        self.layout_combo.connect('changed', self.layout_changed)
        
        self.layout_pref_button = gtk.Button(stock = gtk.STOCK_PREFERENCES)
        self.layout_pref_button.set_sensitive(False)
        self.layout_pref_button.connect('clicked', self.layout_show_pref)
        self.layout_about_button = gtk.Button(stock = gtk.STOCK_ABOUT)
        self.layout_about_button.set_sensitive(True)
        self.layout_about_button.connect('clicked', self.layout_show_about)
        hbox.pack_end(self.layout_pref_button, False, False)
        hbox.pack_end(self.layout_about_button, False, False)
        
        label = gtk.Label(_("Plugins"))
        label.set_attributes(attrlist)
        tbox = gtk.HBox()
        tbox.pack_start(label, False, False)
        vbox.pack_start(tbox, False, False, 5)
        
        self.pixbufs = {
                'extra': gtk.icon_theme_get_default().load_icon('etude-plugin-extra', 32, 0),
                'panel': gtk.icon_theme_get_default().load_icon('etude-plugin-panel', 32, 0)}

        self.plugin_model = gtk.ListStore(gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
        #loaded, icon, short name, short info, uniq name
        self.__fill_plugin_model(self.plugin_model)
        self.plugin_list = gtk.TreeView(self.plugin_model)
        self.plugin_list.set_rules_hint(True)
        self.plugin_list.set_headers_visible(False)
        self.plugin_list.get_selection().connect('changed', self.on_plugin_change)
        scroll = gtk.ScrolledWindow()
        scroll.add(self.plugin_list)
        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroll.set_shadow_type(gtk.SHADOW_IN)

        vbox.pack_start(scroll, True, True)

        hbox1 = gtk.HBox()
        vbox.pack_start(hbox1, False, False)
        self.plugin_pref_button = gtk.Button(stock = gtk.STOCK_PREFERENCES)
        self.plugin_pref_button.set_sensitive(False)
        self.plugin_pref_button.connect('clicked', self.plugin_show_pref)
        self.plugin_about_button = gtk.Button(stock = gtk.STOCK_ABOUT)
        self.plugin_about_button.set_sensitive(False)
        self.plugin_about_button.connect('clicked', self.plugin_show_about)
        hbox1.pack_end(self.plugin_pref_button, False, False)
        hbox1.pack_end(self.plugin_about_button, False, False)

        self.toggle_renderer = gtk.CellRendererToggle()
        self.toggle_renderer.set_data("column", 0)
        self.toggle_renderer.connect("toggled", self.on_plugin_toggled, self.plugin_model)
        column = gtk.TreeViewColumn("", self.toggle_renderer, active = 0)
        # set this column to a fixed sizing(of 50 pixels)
        #column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), col_offset - 1);
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        column.set_fixed_width(20)
        column.set_clickable(True)
        self.plugin_list.append_column(column)
 
        coll = gtk.TreeViewColumn()
        render_pixbuf = gtk.CellRendererPixbuf()
        coll.pack_start(render_pixbuf, expand = False)
        coll.add_attribute(render_pixbuf, 'pixbuf', 1)
        render_text = gtk.CellRendererText()
        coll.pack_start(render_text, expand = True)
        coll.add_attribute(render_text, 'markup', 3)
        self.plugin_list.append_column(coll)

        self.control.connect('g_plugin_panel_loaded', self.on_plugin_loaded, True)
        self.control.connect('g_plugin_extra_loaded', self.on_plugin_loaded, True)
        self.control.connect('g_plugin_panel_unloaded', self.on_plugin_loaded, False)
        self.control.connect('g_plugin_extra_unloaded', self.on_plugin_loaded, False)

        self.show_all()

    def on_plugin_loaded(self, control, unique, load):
        model = self.plugin_model
        for row in model:
            if row[4] == unique:
                if row[0] == load:
                    return
                self.toggle_renderer.handler_block_by_func(self.on_plugin_toggled)
                row[0] = load
                self.toggle_renderer.handler_unblock_by_func(self.on_plugin_toggled)

    def __fill_layout(self, model):
        model.clear()
        layouts = self.control.layouts
        curr_lay = self.control.layout
        for i in xrange(len(layouts)):
            name = layouts[i]._show_name
            if name is None:
                name = layouts[i]._short_name
            iter = model.append( (name, i))
            if isinstance(curr_lay, layouts[i]):
                self.layout_combo.set_active_iter(iter)

    def __fill_plugin_model(self, model):
        def get_name_info(plugin):
            info = plugin._short_descr
            if info is None:
                info = max(plugin.__doc__,"").strip().split('\n')[0]
            name = plugin._show_name
            if name is None:
                name = plugin._short_name
            return (name,info)

        model.clear()
        for plugin in self.control.available_panels.values():
            loaded = False
            if plugin._unique in self.control.loaded["PluginPanels"]:
                loaded = True
            model.append( (loaded, self.pixbufs['panel'], plugin._short_name,
                "<b>%s</b><i>\n%s</i>" % get_name_info(plugin), plugin._unique) )
        for plugin in self.control.available_extras.values():
            loaded = False
            if plugin._unique in self.control.loaded["PluginExtras"]:
                loaded = True
            model.append( (loaded, self.pixbufs['extra'], plugin._short_name,
                "<b>%s</b><i>\n%s</i>" % get_name_info(plugin), plugin._unique) )
        model.set_sort_column_id(2, gtk.SORT_ASCENDING)
        

    def layout_changed(self, widget, data = None):
        iter = widget.get_active_iter()
        if iter == None:
            return False

        model = widget.get_model()
        ind = model.get_value(iter, 1)
        layout_cls = self.control.layouts[ind]
        self.control.unload_layout(config = False)
        self.control.load_layout(layout_cls)
        self.layout_pref_button.set_sensitive( hasattr(layout_cls, 'show_preferences'))

    def on_plugin_toggled(self, widget, path, data = None):
        def show_error_load():
            d = gtk.MessageDialog(parent = self.get_toplevel(),
                    type = gtk.MESSAGE_ERROR,
                    buttons = gtk.BUTTONS_CLOSE,
                    flags = gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
                    message_format = _("Error loading plugin"))
            d.run()
            d.destroy()

        model = self.plugin_model
        iter = model.get_iter(path)
        uniq = model.get_value(iter, 4)
        load = not model.get_value(iter, 0)
        print(load, uniq)
        toggle = False
        if uniq in self.control.available_panels:
            if load:
                ret, lst = self.control.check_panel(uniq)
                if ret == False:
                    dialog = gtk.MessageDialog(parent = self.get_toplevel(), 
                            type = gtk.MESSAGE_INFO, 
                            flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
                    if len(lst) == 1:
                        dialog.add_buttons(gtk.STOCK_YES, gtk.RESPONSE_YES,
                                gtk.STOCK_NO, gtk.RESPONSE_NO)
                        dialog.set_markup(_("Replace the following active plugin?"))
                        inst = lst[0]
                        dialog.format_secondary_markup("<i>"+inst._short_name+"</i>")
                        ret = dialog.run()
                        dialog.destroy()
                        if ret == gtk.RESPONSE_YES:
                            self.control.unload_panel(inst._unique)
                            if self.control.load_panel(uniq) == False:
                                show_error_load()
                            else:
                                toggle = True
                    else:
                        dialog.add_buttons(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
                        dialog.set_markup(_("In order to activate this plugin please disable one of these plugins:"))
                        dialog.format_secondary_markup("<i>"+
                                ", ".join([inst._short_name for inst in lst])+"</i>")
                        dialog.run()
                        dialog.destroy()
                else: #check panel is True - we can load panel
                    if self.control.load_panel(uniq) == False:
                        show_error_load()
                    else:
                        toggle = True
            else: #load = False -> unload plugin
                self.control.unload_panel(uniq)
                toggle = True
        elif uniq in self.control.available_extras:
            if load:
                if self.control.load_extra(uniq) == False:
                    show_error_load()
                else:
                    toggle = True
            else:
                self.control.unload_extra(uniq)
                toggle = True
        if toggle:
            model.set(iter, 0, load)
        return False

    def on_plugin_change(self, treeselect, data = None):
        model,iter = treeselect.get_selected()
        if iter == None:
            self.plugin_pref_button.set_sensitive(False)
            self.plugin_about_button.set_sensitive(False)
            return
        uniq = model.get_value(iter, 4)
        if self.control.plugin_is_loaded(uniq):
            inst = self.control.get_plugin(uniq)
            self.plugin_about_button.set_sensitive(True)
            if hasattr(inst, 'show_preferences'):
                self.plugin_pref_button.set_sensitive(True)
            else:
                self.plugin_pref_button.set_sensitive(False)
        else:
            self.plugin_about_button.set_sensitive(False)
            self.plugin_about_button.set_sensitive(False)

    def plugin_show_about(self, button, data = None): 
        sel = self.plugin_list.get_selection()
        model, iter = sel.get_selected()
        if iter == None:
            return False
        uniq = model.get_value(iter, 4)
        inst = self.control.get_plugin(uniq)
        if inst == None:
            return False
        if hasattr(inst, 'show_about'):
            inst.show_about(self.get_toplevel())
        else:
            dialog = gtk.AboutDialog()
            dialog.set_name(inst._short_name)
            dialog.set_license (inst.__license__)
            dialog.set_copyright ( inst.__author__)
            dialog.set_version ( inst._version)
            dialog.set_comments( inst.__doc__)
            pixbuf= gtk.icon_theme_get_default().load_icon("etude", 64, 0)
            dialog.set_logo(pixbuf)
            dialog.run()
            dialog.destroy()
        return False


    def plugin_show_pref(self, button, data = None):
        sel = self.plugin_list.get_selection()
        model, iter = sel.get_selected()
        if iter == None:
            return False
        uniq = model.get_value(iter, 4)
        inst = self.control.get_plugin(uniq)
        if inst == None:
            return False
        if hasattr(inst, 'show_preferences'):
            inst.show_preferences(self.get_toplevel())
        return False

    def layout_show_about(self, button, data = None): 
        if hasattr(self.control.layout, 'show_about'):
            inst.show_about(self.get_toplevel)
        else:
            dialog = gtk.AboutDialog()
            dialog.set_name(self.control.layout._short_name)
            dialog.set_license (self.control.layout.__license__)
            dialog.set_copyright ( self.control.layout.__author__)
            dialog.set_version ( self.control.layout._version)
            dialog.set_comments( self.control.layout.__doc__)
            pixbuf= gtk.icon_theme_get_default().load_icon("etude", 64, 0)
            dialog.set_logo(pixbuf)
            dialog.run()
            dialog.destroy()
        return False


    def layout_show_pref(self, button, data = None):
        if hasattr(self.control.layout, 'show_preferences'):
            self.control.layout.show_preferences(self.get_toplevel)
        return False

(
        COLUMN_PREFNAME,
        COLUMN_PREFVALUE,
        COLUMN_EDITABLE,
        COLUMN_EXTRA
        ) = xrange(4)

class ShortcutsFrame(gtk.Frame):

    def __init__(self, control):
        gtk.Frame.__init__(self)
        self.control =control
        self.config = control.config
        
        self.set_shadow_type(gtk.SHADOW_NONE)

        self.vbox = gtk.VBox(False, 5)
        self.add(self.vbox)

        label = gtk.Label()
        label.set_markup("<b>"+_("Keyboard shortcuts")+"</b>\n"+
                _("""Here you can change keyboard shortcuts for various actions.
Select one and press the Change button to enter a new shortcut,
or double click an action to edit the string representation of the
shortcut directly."""))
        
        self.vbox.pack_start(label, False, False)

        sw = gtk.ScrolledWindow()
        sw.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.vbox.pack_start(sw)

        self.model = self.__create_model()
        self.__fill_model()
        treeview = gtk.TreeView(self.model)
        treeview.set_rules_hint(True)
        treeview.get_selection().set_mode( gtk.SELECTION_SINGLE)

        self.__add_columns(treeview)
        sw.add(treeview)
        treeview.expand_all()

        change_button = gtk.Button(_("C_hange"))
        change_button.connect("clicked", self.show_change_dialog, treeview)
        self.vbox.pack_start(change_button, False, False, 3)

        self.show_all()
        self.control.connect("g_plugin_loaded", self.changed)
        self.control.connect("g_plugin_unloaded", self.changed)

    def __create_model(self):

        #create list store
        model = gtk.TreeStore(
                gobject.TYPE_STRING, 
                gobject.TYPE_STRING,
                gobject.TYPE_BOOLEAN,
                gobject.TYPE_STRING
                )
        return model

    def save_actions(self, widget, data=None):
        self.control.actions.save()

    def __fill_model(self):
        #add items
        self.model.clear()
        for actiongroup in self.control.uimanager.get_action_groups():
            parent = self.model.append(None)
            self.model.set(parent,
                    COLUMN_PREFNAME, actiongroup.get_name(),
                    COLUMN_PREFVALUE, "",
                    COLUMN_EDITABLE, False,
                    COLUMN_EXTRA, ""
                    )
            for action in actiongroup.list_actions():
                accel_path = action.get_accel_path()
                key,mods = gtk.accel_map_lookup_entry(accel_path)
                accel_name = gtk.accelerator_name(key, mods)
                self.model.append(parent, 
                        (action.get_label().replace('_', ''), 
                            accel_name,True, accel_path)
                        )

        self.model.set_sort_column_id(COLUMN_PREFNAME, gtk.SORT_ASCENDING)

    def __add_columns(self, treeview):

        model = treeview.get_model()

        #prefname column
        renderer = gtk.CellRendererText()
        renderer.set_data("column", COLUMN_PREFNAME)

        column = gtk.TreeViewColumn(_("Action"), renderer, text = COLUMN_PREFNAME)
        treeview.append_column(column)

        #prefvalue column
        renderer = gtk.CellRendererText()
        renderer.connect("edited", self.on_cell_edited)
        renderer.set_data("column", COLUMN_PREFVALUE)

        column = gtk.TreeViewColumn(_("Shortcut"), renderer, text = COLUMN_PREFVALUE, 
                editable = COLUMN_EDITABLE)
        treeview.append_column(column)

    def show_change_dialog(self, button, treeview):
        def _set_combination(widget, event, label):
            key_string = gtk.accelerator_name(event.keyval, event.state)
            #leave only named modifiers
            key_string = reg_mods.sub('', key_string)
            label.set_text(key_string)

        def _response_cb(dialog, response_id, label):
            key_string = label.get_text()
            if (response_id == gtk.RESPONSE_OK and 
                    key_string != model[iter][COLUMN_PREFVALUE]):
                if self.control.actions.change_accel(accel_path, key_string,
                        dialog_parent=self.get_toplevel()):
                    self.model[iter][1] = key_string
            dd.destroy()
        reg_mods = re.compile(r'<mod[1-5]>', flags=re.I)
        selection = treeview.get_selection()
        model,iter = selection.get_selected()
        accel_path = model[iter][COLUMN_EXTRA]
        if iter is None:
            return False
        dd = gtk.MessageDialog(self.get_toplevel(),
                flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_MODAL,
                type=gtk.MESSAGE_QUESTION,
                buttons=gtk.BUTTONS_OK_CANCEL)
        dd.set_markup(_("Please press the combination of keys you want to use for action:")
                + model[iter][0])
        label = gtk.Label("")
        dd.vbox.pack_start(label, False, False, 1)
        dd.connect('key-press-event', _set_combination, label)
        dd.connect('response', _response_cb, label)
        dd.show_all()
 
    def on_cell_edited(self, cell, path_string, new_text, data = None):

        iter = self.model.get_iter_from_string(path_string)
        action_name = self.model.get_value( iter, COLUMN_PREFNAME)
        accel_path = self.model.get_value( iter, COLUMN_EXTRA)
        column = cell.get_data("column")

        if column == COLUMN_PREFVALUE:
            #if len(new_text.strip()) == 0:
            #    result = gtk.accel_map_change_entry(accel_path, 0, 0, False)
            #    print("result ", gtk.accelerator_parse(''))
            #    return False
            if new_text == self.model[iter][COLUMN_PREFVALUE]:
                return False
            
            if self.control.actions.change_accel(accel_path, new_text, 
                    dialog_parent=self.get_toplevel()):
                self.model[iter][1] = new_text

    def changed(self, widget, name, data=None):
        self.__fill_model()

class AdvancedFrame(gtk.Frame):

    def __init__(self, control):
        gtk.Frame.__init__(self)
        self.control =control
        self.client = control.client
        self.config = self.client.config
        
        self.set_shadow_type(gtk.SHADOW_NONE)

        self.vbox = gtk.VBox(False, 5)
        self.add(self.vbox)

        label = gtk.Label(_("Advanced Controls. Please use other options whenever possible!"))
        self.vbox.pack_start(label, False, False)

        sw = gtk.ScrolledWindow()
        sw.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.vbox.pack_start(sw)

        self.model = self.__create_model()
        self.__fill_model()
        treeview = gtk.TreeView(self.model)
        treeview.set_rules_hint(True)
        treeview.get_selection().set_mode( gtk.SELECTION_SINGLE)

        self.__add_columns(treeview)
        sw.add(treeview)

        self.show_all()
        self.client.connect_after("e_configval_changed", self.changed)

    def __create_model(self):

        #create list store
        model = gtk.ListStore(
                gobject.TYPE_STRING, 
                gobject.TYPE_STRING,
                gobject.TYPE_BOOLEAN
                )
        return model

    def __fill_model(self):
        #add items
        for pref in self.config.keys():
            iter = self.model.append()
            
            self.model.set(iter,
                    COLUMN_PREFNAME, pref,
                    COLUMN_PREFVALUE, self.config[pref],
                    COLUMN_EDITABLE, True
                    )
        self.model.set_sort_column_id(COLUMN_PREFNAME, gtk.SORT_ASCENDING)

    def __add_columns(self, treeview):

        model = treeview.get_model()

        #prefname column
        renderer = gtk.CellRendererText()
        renderer.set_data("column", COLUMN_PREFNAME)

        column = gtk.TreeViewColumn(_("Name"), renderer, text = COLUMN_PREFNAME)
        treeview.append_column(column)

        #prefvalue column
        renderer = gtk.CellRendererText()
        renderer.connect("edited", self.on_cell_edited)
        renderer.set_data("column", COLUMN_PREFVALUE)

        column = gtk.TreeViewColumn(_("Value"), renderer, text = COLUMN_PREFVALUE, 
                editable = COLUMN_EDITABLE)
        treeview.append_column(column)
    
    def on_cell_edited(self, cell, path_string, new_text, data = None):

        iter = self.model.get_iter_from_string(path_string)
        prefname = self.model.get_value( iter, COLUMN_PREFNAME)
        column = cell.get_data("column")

        if column == COLUMN_PREFVALUE:
            self.config.set(prefname, new_text)

    def changed(self, widget, key, value):
        self.model.clear()
        self.__fill_model()

